﻿using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Web;
using System.Web.Mvc;
using Microsoft.AspNet.Identity;
using Moq;
using NUnit.Framework;
using Prav.Contracts;
using prav.Controllers;
using Prav.Model;
using prav.Models;

namespace Test
{
    [TestFixture]
    class LentaControllerTests
    {
        private LentaController _lentaController;
        private Mock<IDal> _dalMock;

        [SetUp]
        public void SetUp()
        {
            var mockPosts = new InMemoryDbSet<Post>();
            _dalMock = new Mock<IDal>();
            _dalMock.SetupProperty(dal => dal.Posts, mockPosts);
            _dalMock.Setup(dal => dal.SaveChanges()).Returns(1);

            Mock<IDalFactory> dalFactoryMock = new Mock<IDalFactory>();
            dalFactoryMock.Setup(factory => factory.Create()).Returns(_dalMock.Object);

            var fakeHttpContext = new Mock<HttpContextBase>();

            var claims = new List<Claim>
            {
                new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "TestName"),
                new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", "1111-2222-3333-FFFF")
            };
            var genericIdentity = new GenericIdentity("TestName");
            genericIdentity.AddClaims(claims);
            var principal = new GenericPrincipal(genericIdentity, null);

            fakeHttpContext.Setup(t => t.User).Returns(principal);
            var controllerContext = new Mock<ControllerContext>();
            controllerContext.Setup(t => t.HttpContext).Returns(fakeHttpContext.Object);

            _lentaController = new LentaController(dalFactoryMock.Object);
            _lentaController.ControllerContext = controllerContext.Object;
        }

        [Test]
        public void AddNewPostTest()
        {
            //arrage
            NewPostViewModel testPost = new NewPostViewModel
            {
                Header = "hhh",
                Body = "bbb",
                ParentId = null,
            };

            //act
            var res = (RedirectToRouteResult)_lentaController.New(testPost);

            //assert
            Assert.AreEqual(1, _dalMock.Object.Posts.Count());
            var p = _dalMock.Object.Posts.First();
            Assert.AreEqual(testPost.Header, p.Header);
            Assert.AreEqual(testPost.Body, p.Body);
            Assert.AreEqual(null, testPost.ParentId);
            Assert.AreEqual(p.AuthorUserId, "1111-2222-3333-FFFF");
            Assert.AreEqual(res.RouteValues.Keys.First(), "action");
            Assert.AreEqual(res.RouteValues.Values.First(), "Index");
        }

        [Test]
        public void AddCommentTest()
        {
            //arrage
            NewPostViewModel testPost = new NewPostViewModel
            {
                Header = "comment",
                Body = "body comment",
                ParentId = 111,
            };

            //act
            var res = (RedirectToRouteResult)_lentaController.New(testPost);

            //assert
            Assert.AreEqual(1, _dalMock.Object.Posts.Count());
            var p = _dalMock.Object.Posts.First();
            Assert.AreEqual(testPost.Header, p.Header);
            Assert.AreEqual(testPost.Body, p.Body);
            Assert.AreEqual(testPost.ParentId, testPost.ParentId);
            Assert.AreEqual(p.AuthorUserId, "1111-2222-3333-FFFF");
            Assert.AreEqual(res.RouteValues.Keys.First(), "action");
            Assert.AreEqual(res.RouteValues.Values.First(), "ShowPost/111");
            
        }

        [Test]
        public void NewPostValidationErrorTest()
        {
            //arrage
            NewPostViewModel testPost = new NewPostViewModel
            {
                Header = null,
                Body = "bbb"
            };
            _lentaController.ViewData.ModelState.AddModelError("T", "T");

            //act
            var res = (ViewResult)_lentaController.New(testPost);

            //assert
            Assert.AreEqual(0, _dalMock.Object.Posts.Count());
            Assert.That(res.ViewData.Model, Is.EqualTo(testPost));
        }

        [Test]
        public void ShowPostTest()
        {
            //arrage
            var testPost = ArrageShowPostTest();

            //act
            var res = (ViewResult)_lentaController.ShowPost(33);

            //assert
            var viewModel = (ShowPostViewModel)res.ViewData.Model;
            Assert.AreEqual(viewModel.Post.Id, testPost.Id);
            Assert.AreEqual(viewModel.Post.Header, testPost.Header);
            Assert.AreEqual(viewModel.Post.Body, testPost.Body);
            Assert.AreEqual(viewModel.Post.AccessLevel, testPost.AccessLevel);
            Assert.AreEqual(viewModel.Post.Approved, testPost.Approved);
            Assert.AreEqual(viewModel.Post.Author.Id, testPost.Author.Id);
        }

        private Post ArrageShowPostTest()
        {
            _dalMock.Object.Posts.Add(new Post
            {
                Id = 0,
                AccessLevel = 0,
                Approved = false,
                Author = new ApplicationUser() {Id = "11111", UserName = "User1"},
                Header = "header1",
                Body = "body1",
                Parent = null,
            });

            Post post = new Post
            {
                Id = 33,
                AccessLevel = 3,
                Approved = false,
                Author = new ApplicationUser() {Id = "222222", UserName = "User2"},
                Header = "header2",
                Body = "body2",
                Parent = null,
            };
            _dalMock.Object.Posts.Add(post);

            var p = new Post
            {
                Id = 75,
                AccessLevel = 0,
                Approved = false,
                Author = new ApplicationUser() {Id = "11111", UserName = "User1"},
                Header = "header75",
                Body = "body75",
                Parent = null,
            };

            _dalMock.Object.Posts.Add(p);
            
            p.Comments = new List<Post>();
            var c1 = new Post
            {
                Id = 81,
                AccessLevel = 0,
                Approved = false,
                Author = new ApplicationUser() { Id = "2223", UserName = "User31" },
                Header = "header999cc",
                Body = "body999cc",
                Parent = p,
                ParentId = 75,
            };
            p.Comments.Add(c1);
            _dalMock.Object.Posts.Add(c1);

            var c2 = new Post
            {
                Id = 81,
                AccessLevel = 0,
                Approved = false,
                Author = new ApplicationUser() { Id = "2223", UserName = "User31" },
                Header = "header999cc",
                Body = "body999cc",
                Parent = p,
                ParentId = 75,
            };
            p.Comments.Add(c2);
            _dalMock.Object.Posts.Add(c2);

            return post;
        }

        [Test]
        public void ShowPostWithCommentsTest()
        {
            //arrage
            ArrageShowPaostWithCommentsTest();

            //act
            var res = (ViewResult)_lentaController.ShowPost(75);

            //assert
            var viewModel = (ShowPostViewModel)res.ViewData.Model;
            Assert.AreEqual(viewModel.Post.Comments.Count(), 2);
        }

        private void ArrageShowPaostWithCommentsTest()
        {
            ArrageShowPostTest();
        }

        [Test]
        public void NoCommentsInLentaTest()
        {
            //arrage
            ArrageShowPaostWithCommentsTest();

            //act
            var res = (ViewResult)_lentaController.Index();

            //assert
            var viewModel = (PostsLentaViewModel)res.ViewData.Model;
            Assert.AreEqual(3, viewModel.Posts.Count());
            
        }
    }
}